package com.util.vmwareops;
import com.vmware.vim25.RuntimeFault;
import com.vmware.vim25.mo.*;

import java.rmi.RemoteException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.text.MessageFormat;

import java.util.Map;
import java.util.HashMap;

public class VCenterOps {

    // 更新VC信息后，需要将cluster、host、vm信息都更新一下
    public static Map<String, NetworkInfo> getNetworkInfo(List<ClusterComputeResource> clusterList, VCenterInfo vc, String versionId) {
        Map<String, NetworkInfo> networkInfoMap = new HashMap<String, NetworkInfo>();
        for(ClusterComputeResource cluster : clusterList) {
            Network[] networks = cluster.getNetworks();
            for (Network network : networks) {
                if (!networkInfoMap.containsKey(network.getName())) {
                    networkInfoMap.put(network.getName(), new NetworkInfo(
                            MyUtils.getUUID("Network"),
                            vc,
                            network.getName(),
                            network.getSummary().network.type,
                            versionId
                    ));
                }
            }
        }
        return networkInfoMap;
    }
    public static Map<String, DatastoreInfo> getDatastoreInfo(List<ClusterComputeResource> clusterList, VCenterInfo vc, String versionId) {
        Map<String, DatastoreInfo> datastoreInfoMap = new HashMap<String, DatastoreInfo>();
        for(ClusterComputeResource cluster : clusterList) {
            Datastore [] datastores = cluster.getDatastores();
            for(Datastore datastore : datastores) {
                //System.out.println(datastore.getSummary());
                if(datastore.getName().startsWith("datastore_")){
                    continue;
                }
                if(!datastoreInfoMap.containsKey(datastore.getName())) {
                    datastoreInfoMap.put(datastore.getName(), new DatastoreInfo(
                            MyUtils.getUUID("Datastore"),
                            vc,
                            datastore.getName(),
                            datastore.getSummary().capacity,
                            0,
//                            datastore.getSummary().uncommitted,
                            datastore.getSummary().freeSpace,
                            versionId
                    ));
                }
            }
        }
        return datastoreInfoMap;
    }
    public static synchronized void updateVCenterResourceInfo(VCenterInfo vc, VCConnectionPool vcPool, String versionId) throws Exception {
        // 日志
        System.out.println(String.format("[INFO] Update VC:%s start", vc.getHostname()));

        // 从VC连接池中获取VC连接
        ServiceInstance si = vcPool.getConnnection();

        // 日志
        System.out.println("Get VC Connection !");

        // 获取DB连接池连接
        DBConnectionPool dbPool = DBConnectionPoolFactory.getDBConnectionPool("vmwareops");
        Connection con = dbPool.getConnection();
        con.setAutoCommit(false);

        // 获取集群资源信息
        List<ClusterComputeResource> clusterList = VCenterOps.getCluster(si);

        // 获取VC上所有的网络和存储信息，并更新写入数据库
        Map<String, NetworkInfo> networkInfoMap = getNetworkInfo(clusterList, vc, versionId);
        Map<String, DatastoreInfo> datastoreInfoMap = getDatastoreInfo(clusterList, vc, versionId);
        NetworkOps.updateNetwork(con, networkInfoMap, versionId);
        DatastoreOps.updateDatastore(con, datastoreInfoMap, versionId );

        // 更新集群数据库，并返回集群的信息类列表，方便后续更新host（获取cluster id）
        List<ClusterInfo> clusterInfo = ClusterOps.updateCluster(con, vc, clusterList,versionId);
        vc.setClusters(clusterInfo);

        // 遍历集群列表，获取和更新主机、虚拟机信息
        for (int i=0;i<clusterList.size();i++) {
            // 获取物理主机列表
            HostSystem[] hosts = clusterList.get(i).getHosts();
            // 更新物理主机数据库, 返回物理主机信息，方便更新VM信息
            List<HostInfo> hostInfo = HostOps.updateHost(con, clusterInfo.get(i),hosts, versionId);
            clusterInfo.get(i).setHosts(hostInfo);

            // 遍历物理主机列表，获取和更新虚拟机、存储信息
            for (int j=0;j<hostInfo.size();j++) {
                // 更新虚拟机信息
                VirtualMachine[] vms = hosts[j].getVms();
                List<VMInfo> vmInfo = VirtualMachineOps.updateVM(con, hostInfo.get(j), vms, versionId);
                hostInfo.get(j).setVms(vmInfo);

                // 更新主机的网络信息
                Network[] networks = hosts[j].getNetworks();
                List<NetworkInfo> networkInfos = new ArrayList<NetworkInfo>();
                for(Network network : networks) {
                    networkInfos.add(networkInfoMap.get(network.getName()));
                }
                hostInfo.get(j).setNetworks(networkInfos);
                // 更新数据库中物理主机与网络的关系表
                HostOps.updateHostNetwork(con, hostInfo.get(j), networkInfos, versionId);

                // 更新主机的存储信息
                Datastore[] datastores = hosts[j].getDatastores();
                List<DatastoreInfo> datastoreInfos = new ArrayList<DatastoreInfo>();
                for(Datastore datastore : datastores) {
                    datastoreInfos.add(datastoreInfoMap.get(datastore.getName()));
                }
                hostInfo.get(j).setDatastores(datastoreInfos);
                // 更新数据库中物理主机与存储的关系表
                HostOps.updateHostDatastore(con, hostInfo.get(j), datastoreInfos, versionId);
            }
        }


        con.commit();
        con.setAutoCommit(true);
        dbPool.close(con);
        vcPool.close(si);

        System.out.println(String.format("[INFO] Update VC:%s end", vc.getHostname()));
    }

    // 验证VC是否能够连接
    public static boolean checkVCenter(VCConnectionPool vcPool) {
        try {
            ServiceInstance si = vcPool.getConnnection();
            si.currentTime();
            return true;
        } catch (InterruptedException e) {
            e.printStackTrace();
            return false;
        } catch(RuntimeFault e) {
            return false;
        } catch (RemoteException e) {
            return false;
        } finally {
            vcPool.closeAll();
        }

    }

    // 插入VC数据并更新cluster、host和vm信息，用于新增VC
    public static synchronized boolean InsertVCenterAndUpdateResourceInfo(VCenterInfo vcInfo) throws InterruptedException {

        VCConnectionPool vcPool = VCConnectionPoolFactory.getVCConnectionPoolByVCInfo(vcInfo);
        // 插入前先验证是否能够联通
        if(checkVCenter(vcPool) == false) {
            return false;
        }

        DBConnectionPool dbPool = DBConnectionPoolFactory.getDBConnectionPool("vmwareops");
        Connection con = dbPool.getConnection();
        String sqlCommand = String.format(
                        "insert into resource_bundle_vc values(\"%s\", \"%s\", %s, %s, \"%s\", %d, \"%s\", \"%s\")",
                        vcInfo.getId(),
                        vcInfo.getName(),
                        "sysdate()",
                        "sysdate()",
                        vcInfo.getHostname(),
                        vcInfo.getPort(),
                        vcInfo.getUsername(),
                        vcInfo.getPassword()
                );

        Statement stmt = null;

        try {
            stmt = con.createStatement();
            stmt.execute(sqlCommand);
            if(stmt!=null) {
                stmt.close();
            }
            AllVMwareInfoOps.updateAllResourceInfo();
            return true;
        } catch (SQLException e) {
            e.printStackTrace();
            return false;
        } finally {
            dbPool.closeAll();
        }
    }

    // 更新VC信息
    public static synchronized boolean updateVCenterAndUpdateResourceInfo(VCenterInfo vcInfo) throws InterruptedException {
        DBConnectionPool dbPool = DBConnectionPoolFactory.getDBConnectionPool("vmwareops");
        Connection con = dbPool.getConnection();
        Statement stmt = null;
        try {
            stmt = con.createStatement();
            String sqlCommand = String.format(
                    "update resource_bundle_vc " +
                            "set name=\"%s\", created_at=%s, udpated_at=%s, hostname=\"%s\", port=%d, username=\"%s\", password=\"%s\" " +
                            "where id=\'%s\'",
                    vcInfo.getName(),
                    "sysdate()",
                    "sysdate()",
                    vcInfo.getHostname(),
                    vcInfo.getPort(),
                    vcInfo.getUsername(),
                    vcInfo.getPassword(),
                    vcInfo.getId()
            );
            stmt.execute(sqlCommand);
            if(stmt != null) {
                stmt.close();
            }
            return true;
        } catch(SQLException e) {
            e.printStackTrace();
            return false;
        } finally {
            dbPool.close(con);
        }
    }

    // 删除VC，并更新cluster、host、VM信息
    public static synchronized boolean deleteVCenterAndUpdateResourceInfo(String sqlCommand) throws InterruptedException {
        DBConnectionPool dbPool = DBConnectionPoolFactory.getDBConnectionPool("vmwareops");
        Connection con = dbPool.getConnection();
        Statement stmt = null;
        try {
            stmt = con.createStatement();
            stmt.execute(sqlCommand);
            if(stmt != null) {
                stmt.close();
            }
            AllVMwareInfoOps.setLastGetAllResourceInfoTime(-1000000);
            return true;
        } catch(SQLException e) {
            e.printStackTrace();
            return false;
        } finally {
            dbPool.close(con);
        }
    }
    // 通过名字删除VC
    public static synchronized boolean deleteVCenterAndUpdateResourceInfoByName(VCenterInfo vcInfo) throws InterruptedException {
        String sqlCommand = String.format(
                "delete from resource_bundle_vc where name=\'%s\' and hostname=\'%s\'",
                vcInfo.getName(),
                vcInfo.getHostname()
        );
        return deleteVCenterAndUpdateResourceInfo(sqlCommand);
    }
    //通过id号删除VC
    public static synchronized boolean deleteVCenterAndUpdateResourceInfoById(VCenterInfo vcInfo) throws InterruptedException {
        String sqlCommand = String.format(
                "delete from resource_bundle_vc where id=\'%s\'",
                vcInfo.getId()
        );
        return deleteVCenterAndUpdateResourceInfo(sqlCommand);
    }
    public static List<VCenterInfo> getAllVCInfo() throws InterruptedException {
        DBConnectionPool db = DBConnectionPoolFactory.getDBConnectionPool("vmwareops");
        Connection con = db.getConnection();
        List<VCenterInfo> vc = new ArrayList<VCenterInfo>();
        String sql = String.format("select * from %s", "resource_bundle_vc");
        try {
            Statement stmt = con.createStatement();
            ResultSet res = stmt.executeQuery(sql);
            if(res == null) {
                return null;
            }
            while(res.next()) {
                vc.add(
                        new VCenterInfo(
                                res.getString("id"),
                                res.getString("name"),
                                res.getString("hostname"),
                                res.getInt("port"),
                                res.getString("username"),
                                res.getString("password")
                        )
                );
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if(con != null) {
                db.close(con);
            }
        }
        return vc;
    }
    // 从VC中拉取集群信息
    public static List<ClusterComputeResource> getCluster(ServiceInstance si) throws Exception {

        // 获取根目录
        Folder rootFolder = si.getRootFolder();

        // 获取集群资源
        ManagedEntity[] managedEntityList;
        managedEntityList = new InventoryNavigator(rootFolder).searchManagedEntities("ClusterComputeResource");
        // 遍历集群资源，获取物理主机和虚拟机
        // 获取集群列表
        List<ClusterComputeResource> clusterList = new ArrayList<ClusterComputeResource>();
        for (ManagedEntity entity : managedEntityList) {
            ClusterComputeResource cluster = (ClusterComputeResource) entity;
            clusterList.add(cluster);
        }
        return clusterList;
    }
}

